package com.afc.struts;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.afc.struts.asserts.ActionException;
import com.afc.struts.form.ActionForm;
import com.afc.struts.form.ActionFormFactory;
import com.afc.struts.form.ActionFormFactory.DefaultActionFormFactory;
import com.afc.struts.mapping.ActionMapping;
import com.afc.struts.mapping.ActionMappingFactory;
import com.afc.struts.utils.LabeledBoolean;
import com.afc.struts.utils.Report;
import com.afc.struts.xml.XmlActionMappingFactory;

@SuppressWarnings("serial")
public class ActionServlet extends HttpServlet
{
  @Override
  public void init(ServletConfig aServletConfig) throws ServletException
  {
    super.init(aServletConfig);
    actionMappingFactory = new XmlActionMappingFactory(aServletConfig);
    actionFormFactory = new DefaultActionFormFactory(aServletConfig);
  }

  @Override
  protected void doGet(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException
  {
    doPost(aRequest, aResponse);
  }

  @Override
  protected void doPost(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException
  {
    try
    {
      String url = aRequest.getServletPath();
      ActionMapping actionMapping = actionMappingFactory.getActionMapping(url);
      String next = execute(actionMapping, aRequest, aResponse);
      forward(next, aRequest, aResponse);
    }
    catch (ActionException anException)
    {
      throw new ServletException("Unable to operate request", anException);
    }
  }

  @SuppressWarnings("unchecked")
  protected String execute(ActionMapping anActionMapping, HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, ActionException
  {
    ActionForm form = actionFormFactory.getActionForm(anActionMapping.getFormClass(), aRequest);
    LabeledBoolean validate = form.validateForm();
    String next = null;
    if (validate.isTrue() && aRequest.getAttribute(ERROR_REQUEST_ATTRIBUTE_NAME) == null)
    {
      next = anActionMapping.getAction().execute(form, aRequest, aResponse);
    }
    else
    {
      aRequest.setAttribute(FORM_REQUEST_ATTRIBUTE_NAME, form);
      if (!validate.isTrue())
      {
        Report.error("Invalid Form", validate.getInfos(), aRequest);
      }
    }
    if (next == null)
    {
      next = anActionMapping.getOriginalUrl();
    }
    return next;
  }

  protected void forward(String aPath, HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletException, IOException
  {
    ServletContext servletContext = getServletContext();
    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher(aPath);
    requestDispatcher.forward(aRequest, aResponse);
  }

  protected ActionMappingFactory actionMappingFactory;
  protected ActionFormFactory actionFormFactory;

  static public final String FORM_REQUEST_ATTRIBUTE_NAME = "form";
  static public final String ERROR_REQUEST_ATTRIBUTE_NAME = "error";
}
